from typing import Optional, Union, List, Dict, Tuple

from beanie import PydanticObjectId
from fastapi import APIRouter, status
from fastapi.responses import PlainTextResponse

from auth.role.model import Role, RolePermission
from auth.role.service import enforcer

router = APIRouter()


@router.post("/add", response_model=Role)
async def add(obj: Role):
    doc = await obj.insert()
    return doc


@router.delete("/permission")
async def delete_permission(obj: RolePermission):
    enforcer.delete_permission_for_user(obj.identity, obj.path, obj.method)
    return {'detail': 'OK'}


@router.delete("/{_id}", response_model=Role)
async def delete(_id: PydanticObjectId):
    doc = await Role.get(_id)
    if doc:
        await doc.delete()
        return doc
    return PlainTextResponse(status_code=status.HTTP_404_NOT_FOUND, content='Not Found')


@router.put("/{_id}", response_model=Role)
async def update(_id: PydanticObjectId, obj: Role):
    update_query = {"$set": {k: v for k, v in obj.dict().items() if v is not None}}
    doc = await Role.get(_id)
    if doc:
        await doc.update(update_query)
        return doc
    return PlainTextResponse(status_code=status.HTTP_404_NOT_FOUND, content='Not Found')


@router.get("/{_id}", response_model=Role)
async def get_one(_id: PydanticObjectId):
    doc = await Role.get(_id)
    if doc:
        return doc
    return PlainTextResponse(status_code=status.HTTP_404_NOT_FOUND, content='Not Found')


@router.get("/", response_model=List[Role])
async def get_all():
    data = await Role.all().to_list()
    return data


@router.post("/list", response_model=Dict[str, Union[int, List[Role]]])
async def get_list(
        args: Optional[dict] = {},
        page: int = 1, limit: int = 1000,
        sort: Optional[List[Tuple[str, int]]] = [('_id', -1)]):
    count = await Role.find(args).count()
    data = await Role.find(args, skip=(page - 1) * limit, limit=limit, sort=sort).to_list()
    return {
        "count": count,
        "data": data
    }


@router.post("/permission")
async def add_permission(obj: RolePermission):
    enforcer.add_permission_for_user(obj.identity, obj.path, obj.method)
    return {'detail': 'OK'}


@router.get("/{role_id}/permissions")
async def get_permissions(role_id: str):
    return enforcer.get_permissions_for_user(role_id)
